Skip to content

feat(updates): add one-click upgrade experience - #840

Merged
mcharles-square merged 13 commits into
mainfrom
codex/one-click-updates-06-client-experience
Aug 10, 2026
Merged

feat(updates): add one-click upgrade experience#840
mcharles-square merged 13 commits into
mainfrom
codex/one-click-updates-06-client-experience

Conversation

@mcharles-square

@mcharles-square mcharles-square commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Reviewable diff: +917/-8 across 5 files (excludes generated, test, and story files).

Summary

Adds the one-click upgrade workflow to Settings > Updates: exact-version confirmation, RC warnings, durable progress, expected restart recovery, failure guidance, and success reload. The normal application shell remains intentionally passive—it only advertises an available version and routes operators to Settings—while unsupported hosts retain the release-specific manual install command.

Stack: #841#842#843#844#845#835#836#837#838#839#840. This is 6/6 of the one-click phase and the diff is relative to #839. The merged ancestors provide release discovery, permission-gated APIs, durable host execution, and the passive update indicator; #839 installs that executor on supported hosts. Host mutation is intentionally out of scope here, and progress is intentionally not tracked across every Fleet view.

How it works

The passive version pill navigates an authorized operator to /settings/updates. The route loads the current eligible release, capability, and manual command, while separately checking durable updater status so an operation started in another tab or recovered after navigation takes precedence over a newer offer. A one-click action appears only when Fleet reports a reachable executor; confirmation sends only the exact eligible version, and fleetd revalidates it before host mutation.

During an operation the route uses completion-based polling, preserves the last phase through the expected Fleet restart, and recovers host state when the operator returns. Ambiguous trigger outcomes keep competing controls locked. If the executor remains unreachable after the bounded reconciliation window, the manual command stays locked until the operator explicitly confirms on-host that no upgrade is running; a reachable executor reporting no matching operation instead refreshes the eligible release before retry.

flowchart LR
  S["Passive version pill"] --> R["Settings > Updates"]
  R --> U["GetUpdateStatus: release, capability, manual command"]
  R --> O["GetUpgradeStatus: durable host operation"]
  U --> C{"Executor reachable?"}
  C -->|"yes"| X["Confirm exact target"]
  C -->|"no"| M["Copy manual install command"]
  X --> T["TriggerUpgrade(target version)"]
  T --> P["Route-owned progress and recovery"]
  O --> P
  P --> F["Failure details or explicit manual fallback"]
  P --> D["Success and reload"]
Loading
sequenceDiagram
  participant U as "Authorized operator"
  participant S as "Fleet shell"
  participant R as "Updates route"
  participant F as "fleetd"
  participant X as "Host updater"

  S->>F: "Discover eligible version"
  F-->>S: "Version-only indicator"
  U->>S: "Open update"
  S->>R: "Navigate to /settings/updates"
  R->>F: "GetUpdateStatus + GetUpgradeStatus"
  F-->>R: "Offer, capability, durable operation"
  U->>R: "Confirm exact target"
  R->>F: "TriggerUpgrade(target version)"
  F->>X: "Start validated operation"
  R-->>F: "Poll without overlap"
  opt "Operator leaves the route"
    U->>R: "Return later"
    R->>F: "Recover durable status"
  end
  F-->>R: "Active, failed, or succeeded"
  R-->>U: "Progress, recovery, or reload"
Loading

Areas of the code involved

Area / package / file What changed Why it matters for review
features/settings/components/Updates.tsx Owns capability-gated actions, control locking, status reconciliation, and route-level recovery Confirms the workflow stays local to Settings and preserves the manual path
features/settings/components/UpgradeOperationModal.tsx Adds confirmation, RC warning, progress, reconnect, failure, success, and explicit manual-unlock states Primary operator-facing safety surface
features/updates/api/useUpgradeOperation.ts Adds bounded RPCs, non-overlapping polling, session recovery, durable-operation precedence, and ambiguous-outcome handling Core lifecycle and concurrency review surface
copyInstallCommand.ts Updates the stale ownership comment after removing the global modal Confirms the helper now serves the Settings fallback
Focused client tests Covers route integration, lifecycle transitions, target preservation, auth loss, disconnects, and fallback confirmation Tests — review alongside each state owner
docs/plans/archive/...one-click-upgrade...md Records the completed route-owned architecture and current trust/recovery boundaries Institutional context for future maintenance

Key technical decisions & trade-offs

  • Settings owns confirmation and progress; the shell keeps only a passive link, avoiding lifecycle state across every route.
  • Durable host status is authoritative; browser session storage records only which terminal result belongs to this tab and survives route remounts.
  • Polls schedule only after the prior request completes, with bounded RPCs, avoiding overlapping requests during a restart.
  • An active host operation supersedes a newer release offer; the UI never exposes two competing targets.
  • Unknown trigger outcomes fail closed. Manual fallback requires explicit host confirmation after the bounded wait rather than silently unlocking a potentially overlapping install.
  • Failed operations retain the established manual command and expose the host log/recovery command; automatic rollback remains out of scope because migrations are forward-only.

Testing & validation

  • 79 focused Vitest cases passed across Settings integration, upgrade lifecycle, modal states, the passive indicator, and AppLayout behavior.
  • Full client ESLint and TypeScript typechecking passed; npm run build:protoFleet passed the production Vite build.
  • The full local unit run completed 4,013 tests successfully; one unrelated QR/WASM suite could not load through this worktree's symlinked node_modules path and is left to the normal CI checkout.
  • Pre-commit formatting and pre-push typecheck hooks passed.
  • Real systemd/rootful-Docker activation is intentionally covered by the preceding host PRs rather than browser unit tests.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated security-focused code review generated by Codex.
It should be used as a supplementary check alongside human review.
False positives are possible - use your judgment.

Scope summary

  • Reviewed pull request diff only (419b58d216dc3686f35335eff1fb838b3463d331...6b5dd2a079b42efdc57b54f06a705158c97514d1, exact PR three-dot diff)
  • Model: gpt-5.6-sol

💡 Click "edited" above to see previous reviews for this PR.


Review Summary

Overall Risk: MEDIUM

Findings

[MEDIUM] Disabled fallback still exposes the shell command

  • Category: Concurrency
  • Location: client/src/protoFleet/features/settings/components/Updates.tsx:466
  • Description: During an active or uncertain upgrade, only the copy button is disabled. The complete manual installation command remains rendered immediately beside it, so it can still be selected or copied from the DOM without performing the explicit fallback-confirmation flow.
  • Impact: An operator can start the manual installer while the host updater is modifying the same deployment. This can interrupt activation, race container or migration operations, and leave Fleet unavailable or requiring manual recovery.
  • Recommendation: Do not render the command value while manualCommandDisabled is true. Reveal it only after fallback confirmation and an authoritative status refresh; ideally, also make the manual installer refuse to run while a host upgrade is active.

[MEDIUM] Sixty-second idle polling misses concurrent upgrades

  • Category: Concurrency
  • Location: client/src/protoFleet/features/updates/api/useUpgradeOperation.ts:497
  • Description: Once this tab sees no operation, it waits 60 seconds before polling again. An upgrade started immediately afterward by another tab or operator remains unknown locally, leaving the manual command and release-channel controls enabled. Trigger conflicts are reconciled server-side, but copying the manual command performs no fresh status check.
  • Impact: A normal multi-operator race can expose and execute a competing manual installation for nearly a minute after the host upgrade begins, risking interruption or deployment damage.
  • Recommendation: Poll at the active cadence while conflicting update controls are exposed, add cross-tab/server-driven invalidation, and revalidate status immediately before revealing or copying a manual command. Host-enforced mutual exclusion is needed to eliminate the final check-to-use race.

Notes

The diff contains no pool or wallet-address modifications or protobuf wire-format changes. Targeted Vitest execution could not run because dependencies were unavailable and restricted networking prevented package resolution.


Generated by Codex Security Review |
Triggered by: @mcharles-square |
Review workflow run

@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from f8c41ce to 9178649 Compare July 30, 2026 08:50
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 9178649 to 4afd98a Compare July 30, 2026 09:03
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch 2 times, most recently from 2ce2ce5 to 5854595 Compare July 30, 2026 14:16
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch from 5854595 to 586f9e7 Compare July 30, 2026 15:25
@mcharles-square
mcharles-square force-pushed the codex/one-click-updates-06-client-experience branch 2 times, most recently from 6fc4d02 to 484cace Compare July 30, 2026 17:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the operator-facing, one-click upgrade workflow to ProtoFleet’s Settings → Updates page, integrating the newly available backend capability and durable upgrade operation status into a route-owned UX (confirmation, progress, recovery, and explicit manual fallback).

Changes:

  • Introduces a useUpgradeOperation hook to trigger upgrades, poll durable status without overlap, and recover/lock state across expected restarts.
  • Adds UpgradeOperationModal to guide operators through confirmation, RC warnings, progress/reconnect, failure recovery details, and success reload.
  • Extends the Updates settings page to surface capability-gated one-click actions, reconcile durable operations vs. newer offers, and lock competing controls appropriately.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/plans/archive/2026-07-29-one-click-upgrade-executor-plan.md Archives the completed plan and documents final boundaries/ownership for the one-click executor workflow.
client/src/protoFleet/features/updates/copyInstallCommand.ts Updates helper comment to reflect Settings-owned manual fallback usage.
client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Adds upgrade lifecycle hook: trigger, bounded reconciliation, non-overlapping polling, and session recovery.
client/src/protoFleet/features/updates/api/useUpgradeOperation.test.tsx Adds focused unit tests for the upgrade operation hook behaviors (recovery, reconciliation, cadence, acknowledgements).
client/src/protoFleet/features/settings/components/UpgradeOperationModal.tsx Implements modal UX for confirmation/progress/failure/success/manual unlock flows.
client/src/protoFleet/features/settings/components/UpgradeOperationModal.test.tsx Adds modal behavior and accessibility assertions for the various states and actions.
client/src/protoFleet/features/settings/components/Updates.tsx Wires one-click upgrade into Settings → Updates, including capability gating, locking, and durable status reconciliation.
client/src/protoFleet/features/settings/components/Updates.test.tsx Extends Settings Updates integration tests for one-click upgrade states and permission revocation handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts
Comment thread client/src/protoFleet/features/settings/components/Updates.test.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14a80be769

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 789da4caf2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cfab18509e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/settings/components/Updates.tsx Outdated
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81d998aa06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33cc70a6c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9fc5722fce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/settings/components/Updates.tsx Outdated
@mcharles-square

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the current Codex Security Review finding in a060c5f. Ambiguous no-ID reconciliation now accepts only a target-matching SUCCEEDED operation, so a completed upgrade is recovered and prompts reload; same-target failures still require exact operation-ID correlation and cannot unlock competing install controls. Added coverage where TriggerUpgrade loses its response and the first subsequent durable status is SUCCEEDED.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a060c5f3cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdc1a5fec3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/settings/components/Updates.tsx
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bad5e6e0f5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated
Comment thread client/src/protoFleet/features/settings/components/Updates.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78375356e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbf954ebef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts Outdated
Comment thread client/src/protoFleet/features/settings/components/Updates.tsx Outdated
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts
Comment thread client/src/protoFleet/features/updates/api/useUpgradeOperation.ts
@github-actions github-actions Bot added review-policy: human-approved Managed by the Review Policy workflow. and removed review-policy: needs-review Managed by the Review Policy workflow. labels Aug 10, 2026
@github-actions github-actions Bot added review-policy: needs-review Managed by the Review Policy workflow. and removed review-policy: human-approved Managed by the Review Policy workflow. labels Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client documentation Improvements or additions to documentation javascript Pull requests that update javascript code review-policy: needs-review Managed by the Review Policy workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants